<?php

namespace App\Common;


use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class Func
{
    /**
     * 定义http请求返回格式
     * @param string $code
     * @param string $message
     * @param array $data
     * @return array
     */
    public static function response($code = '0', $message = '', $data = null): array
    {
        $code = is_string($code) ? (int)$code : $code;
        $codeList = config('errcode.' . $code);
//        if (!env('APP_DEBUG') && ($code > 0 && $code < 10000)) {
//            $message = isset($codeList['code']) ? $codeList['msg'] : "";
//        }
        $message = $message ? $message : (isset($codeList['code']) ? $codeList['msg'] : '');
        $errCode = isset($codeList['code']) ? $codeList['code'] : '';
        return compact('code', 'errCode', 'message', 'data');
    }

    /**
     * 记录error错误信息
     * @param array $params
     * @param string $message
     */
    public static function logError($params = [], $message = "", $title = "")
    {
        Log::error("title:" . $title . "，params:" . json_encode($params, JSON_UNESCAPED_UNICODE) . " message:" . $message);
    }

    /**
     * 记录error错误信息
     * @param array $params
     * @param string $message
     */
    public static function logInfo($params = [], $message = "")
    {
        Log::info("params:" . json_encode($params, JSON_UNESCAPED_UNICODE) . " message:" . $message);
    }

    /**
     * 记录notice错误信息
     * @param array $params
     * @param string $message
     */
    public static function logNotice($params = [], $message = "", $title = "")
    {
        Log::notice("title:" . $title . "，params:" . json_encode($params, JSON_UNESCAPED_UNICODE) . " message:" . $message);
    }

    /**
     * 记录warning错误信息
     * @param array $params
     * @param string $message
     */
    public static function logWarning($params = [], $message = "")
    {
        Log::warning("params:" . json_encode($params, JSON_UNESCAPED_UNICODE) . " message:" . $message);
    }

    /**
     * 发起http请求
     * @param $url
     * @param array $data
     * @param string $method
     * @return array
     */
    public static function http($url, $data = [], $method = 'GET', $timeOut = 5)
    {
        try {
            if ($method == 'GET') {
                $result = Http::timeout($timeOut)
                    ->withHeaders([
                        'token' => env('OUTER_API_TOKEN')
                    ])
                    ->get($url, $data)
                    ->throw()
                    ->json();
            } else {
                $result = Http::timeout($timeOut)
                    ->withHeaders([
                        'token' => env('OUTER_API_TOKEN')
                    ])
                    ->post($url, $data)
                    ->throw()
                    ->json();

            }
            self::logInfo($data, '接口：' . $url . '|' . "返回结果：" . json_encode($result, JSON_UNESCAPED_UNICODE));
            return $result;
        } catch (RequestException $e) {
            $errorMsg = $e->getMessage();
            self::logError($data, '外部接口' . $url . '调用异常, 异常提示内容:' . $errorMsg);
            return self::response(1, '网络开小差~，请稍后');
        } catch (\Throwable $e) {
            if (str_contains(strtolower($e->getMessage()), strtolower('cURL error 28'))) {
                self::logError($data, '外部接口' . $url . '调用异常,原因是：接口超时(' . $timeOut . ')');
                return self::response(1, '网络开小差~，接口超时');
            }
        }
    }

    /**
     * 发起http请求Json格式
     * @param $url
     * @param $data
     * @param string $method
     * @return array
     */
    public static function httpJson($url, $data, $method = 'POST', $timeOut = 5)
    {
        try {
            if ($method == 'GET') {
                $result = Http::asJson()
                    ->timeout($timeOut)
                    ->withHeaders(['token' => env('OUTER_API_TOKEN')])
                    ->get($url, $data)
                    ->throw()
                    ->json();
            } else {
                $result = Http::asJson()
                    ->timeout($timeOut)
                    ->withHeaders(['token' => env('OUTER_API_TOKEN')])
                    ->post($url, $data)
                    ->throw()
                    ->json();
            }
            self::logInfo($data, '接口：' . $url . '|' . "返回结果：" . json_encode($result, JSON_UNESCAPED_UNICODE));
            return $result;
        } catch (RequestException $e) {
            $errorMsg = $e->getMessage();
            self::logError($data, '外部接口' . $url . '调用异常, 异常提示内容:' . $errorMsg);
            return self::response(1, '网络开小差~，请稍后');
        } catch (\Throwable $e) {
            if (str_contains(strtolower($e->getMessage()), strtolower('cURL error 28'))) {
                self::logError($data, '外部接口' . $url . '调用异常,原因是：接口超时(' . $timeOut . ')');
                return self::response(1, '网络开小差~，接口超时');
            }
        }
    }

    /**
     * 生成活动编号
     * @return string
     */
    public static function getRandCode()
    {
        return date('Ymd') . date('md') . substr(time(), -5) . substr(
                microtime(),
                2,
                5
            ) . str_pad(mt_rand(1, 99), 2, '0', STR_PAD_LEFT);
    }

    public static function camelCase($value): string
    {
        return lcfirst(str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $value))));
    }

    public function arrayChangeKeyCaseCamel($array): array
    {
        $result = [];
        foreach ($array as $key => $value) {
            $newKey = self::camelCase($key);
            $result[$newKey] = is_array($value) ? $this->arrayChangeKeyCaseCamel($value) : $value;
        }
        return $result;
    }

    /**
     * 上传
     * @param $target_url
     * @param $filename
     * @param $form_name
     * @return bool|string
     */
    public static function curlUploadFile($target_url, $filename, $form_name)
    {
        $upload_file = new \CURLFile($filename);
        $post_data = array(
            $form_name => $upload_file
        );
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $target_url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * 生成随机6位随机字符串
     * @param int $len
     * @param null $chars
     * @return string
     */
    public static function getRandomString($len = 6, $chars = null)
    {
        if (is_null($chars)) {
            $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        }
        mt_srand(10000000 * (double)microtime());
        for ($i = 0, $str = '', $lc = strlen($chars) - 1; $i < $len; $i++) {
            $str .= $chars[mt_rand(0, $lc)];
        }

        return $str;
    }

    /**
     * 二维数组根据某个字段排序
     * @param array $array 要排序的数组
     * @param string $keys 要排序的键字段
     * @param string $sort 排序类型  SORT_ASC     SORT_DESC
     * @return array 排序后的数组
     */
    public static function arraySort($array, $keys, $sort = SORT_DESC)
    {
        $keysValue = [];
        foreach ($array as $k => $v) {
            $keysValue[$k] = $v[$keys];
        }
        array_multisort($keysValue, $sort, $array);
        return $array;
    }

    /**
     * 计算两点地理坐标之间的距离
     * @param float $longitude1 起点经度
     * @param float $latitude1 起点纬度
     * @param float $longitude2 终点经度
     * @param float $latitude2 终点纬度
     * @param int $unit 单位 1:米 2:公里
     * @param int $decimal 精度 保留小数位数
     * @return float
     */
    public static function getDistance(float $longitude1, float $latitude1, float $longitude2, float $latitude2, int $unit = 1, int $decimal = 2)
    {

        $EARTH_RADIUS = 6378.138; // 地球半径系数
        $PI = 3.1415926;

        $radLat1 = $latitude1 * $PI / 180.0;
        $radLat2 = $latitude2 * $PI / 180.0;

        $radLng1 = $longitude1 * $PI / 180.0;
        $radLng2 = $longitude2 * $PI / 180.0;

        $a = $radLat1 - $radLat2;
        $b = $radLng1 - $radLng2;

        $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
        $distance = $distance * $EARTH_RADIUS * 1000;

        if ($unit == 2) {
            $distance = $distance / 1000;
        }

        return round($distance, $decimal);
    }

    /**
     * 下划线转驼峰
     * 思路:
     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
     * @param $uncamelized_words
     * @param string $separator
     * @return string
     */
    public static function camelize($uncamelized_words, $separator = '_')
    {
        $uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
    }

    /**
     * 手机号加密显示
     * @param $phone
     * @return array|string|string[]
     */
    function hidePhone($phone)
    {
        return substr_replace($phone, '****', 3, -4);
    }

    /**
     * 订单编号自动生成
     * @return string
     */
    public static function createOrderCode($sceneCode): string
    {
        return $sceneCode . date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }


    /**
     * 方法二：获取随机字符串
     * @param int $randLength 长度
     * @param int $addtime 是否加入当前时间戳
     * @param int $includenumber 是否包含数字
     * @return string
     */
    public static function the_str($length = 6, $addtime = 1, $includenumber = 1)
    {
        if ($includenumber) {
            $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789';
        } else {
            $chars = 'abcdefghijklmnopqrstuvwxyz';
        }
        $len = strlen($chars);
        $randStr = '';
        for ($i = 0; $i < $length; $i++) {
            $randStr .= $chars[mt_rand(0, $len - 1)];
        }
        $tokenvalue = $randStr;
        if ($addtime) {
            $tokenvalue = $randStr . time();
        }
        return $tokenvalue;
    }

    public static function calculateZodiac($month, $day)
    {
        if ($month == 1 && $day >= 20 || $month == 2 && $day <= 18) {
            return "水瓶座";
        } elseif ($month == 1 && $day < 20 || $month == 2 && $day > 18) {
            return "双鱼座";
        } elseif ($month == 3 && $day >= 21 || $month == 4 && $day <= 19) {
            return "白羊座";
        } elseif ($month == 3 && $day < 21 || $month == 4 && $day > 19) {
            return "金牛座";
        } elseif ($month == 5 && $day >= 21 || $month == 6 && $day <= 20) {
            return "双子座";
        } elseif ($month == 5 && $day < 21 || $month == 6 && $day > 20) {
            return "巨蟹座";
        } elseif ($month == 7 && $day >= 22 || $month == 8 && $day <= 22) {
            return "狮子座";
        } elseif ($month == 7 && $day < 22 || $month == 8 && $day > 22) {
            return "处女座";
        } elseif ($month == 9 && $day >= 23 || $month == 10 && $day <= 22) {
            return "天秤座";
        } elseif ($month == 9 && $day < 23 || $month == 10 && $day > 22) {
            return "天蝎座";
        } elseif ($month == 11 && $day >= 23 || $month == 12 && $day <= 21) {
            return "射手座";
        } elseif ($month == 11 && $day < 23 || $month == 12 && $day > 21) {
            return "魔羯座";
        }
        return null;
    }

    /**
     * 生成随机uuid
     * @return string
     */
    public static function generateUUid(): string
    {
        return rand(100000000, 999999999);
    }

    /**
     * 生成随机昵称
     * @param int $length
     * @return string
     */
    public static function generateRandomNickname(int $length = 8): string
    {
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $randomString;
    }

    public static function randomAvatar()
    {
        $images = [
            "https://img.beebud.cn/beebud/app/66c8b1f573971.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f67fa58.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f6be36e.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f7056f8.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f746392.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f7800d2.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f7badb0.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f7ee122.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f8390be.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f86d040.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f8a3e41.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f8de052.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f924a37.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f95cf55.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f98f834.jpg",
            "https://img.beebud.cn/beebud/app/66c8b1f9c9ca0.jpg"
        ];
        return $images[rand(0, count($images) - 1)];
    }

    public static function getLocationByIP($ip)
    {
        if (!$ip) {
            return null;
        }
        $cacheKey = "getLocationByIP:" . $ip;
        $location = Cache::get($cacheKey);
        if ($location) return json_decode($location, true);
        $url = "https://apis.map.qq.com/ws/location/v1/ip";
        $data = [
            "key" => "HQ3BZ-JBD3J-3QLFM-DJA2B-WGVQ6-PJBL2",
            "ip" => $ip
        ];
        try {
            $result = Http::get($url, $data)
                ->throw()
                ->json();
            self::logInfo($data, '接口：' . $url . '|' . "返回结果：" . json_encode($result, JSON_UNESCAPED_UNICODE));
        } catch (\Exception $e) {
            self::logError($data, '外部接口' . $url . '调用异常, 异常提示内容:' . $e->getMessage());
            return null;
        }
        if ($result['status'] != 0) {
            return null;
        }
        $data = $result['result'];
        $location = [
            'ip' => $data['ip'],
            'lng' => $data['location']['lng'],
            'lat' => $data['location']['lat'],
            'nation' => $data['ad_info']['nation'],
            'nationCode' => $data['ad_info']['nation_code'],
            'province' => $data['ad_info']['province'],
            'city' => $data['ad_info']['city'],
            'district' => $data['ad_info']['district'],
            'adcode' => $data['ad_info']['adcode'],
        ];
        Cache::put($cacheKey, json_encode($location, JSON_UNESCAPED_UNICODE), 3600 * 24 * 30 * 6);
        return $location;
    }

    public static function getHierarchy($data, $pid = 0)
    {
        $result = [];

        foreach ($data as $item) {
            if ($item['pid'] == $pid) {
                // 递归获取子级
                $item['children'] = self::getHierarchy($data, $item['id']);
                $result[] = $item;
            }
        }

        return $result;
    }
}

